import java.util.ArrayList;
import java.util.TreeSet;

import com.vividsolutions.jts.geom.GeometryFactory;
import com.vividsolutions.jts.geom.Polygon;
import com.vividsolutions.jts.io.ParseException;
import com.vividsolutions.jts.io.WKTReader;

public class PointRangeQuery {
	/*修改前的范围处理方法*/
	private ArrayList<String> searchGeohash(double X1,double Y1,double X2,double Y2) throws ParseException{
		double lonlength;
		double latlength;
		double l,l1;
		double y,x;
		int level,level1;
		if(X1<X2){
			lonlength=X2-X1;
		}
		else {
			lonlength=X2-X1+360;
		}
		latlength=Y2-Y1;
		/*level决定查询范围四个角点从哪一级开始划分，level1决定查询范围的最大划分次数
		 * level由经纬度相对长的一边算出，level1由经纬度相对短的一边算出
		 * */
		if(lonlength>=latlength){
			l=(2*Math.floor(Logarithm.log(360/lonlength, 2))-1);		
			y=180/(Math.pow(2, (l+1)/2));			
			if(latlength<=y){
				level=(int) (l+1);
			}
			else {
				level=(int) l;
			}
			l1=2*Math.floor(Logarithm.log(180/latlength, 2));
			x=360/(Math.pow(2, (l1+2)/2));
			if(lonlength<=x){
				level1=(int) (l1+1);
			}
			else{
				level1=(int) l1;
			}
		}
		else{
			l=2*Math.floor(Logarithm.log(180/latlength, 2));
			x=360/(Math.pow(2, (l+2)/2));
			if(lonlength<=x){
				level=(int) (l+1);
			}
			else{
				level=(int) l;
			}
			l1=(2*Math.floor(Logarithm.log(360/lonlength, 2))-1);
			y=180/(Math.pow(2, (l+1)/2));	
			if(latlength<=y){
				level1=(int) (l1+1);
			}
			else {
				level1=(int) l1;
			}
		}
		/*将查询范围构建成一个Geometry*/
		GeometryFactory geometryFactory=new GeometryFactory();
		WKTReader reader = new WKTReader(geometryFactory);
		String rangePol="POLYGON(("+String.valueOf(X1)+" "+String.valueOf(Y1)+","+" "+String.valueOf(X1)+" "+String.valueOf(Y2)+","+" "+String.valueOf(X2)+" "+String.valueOf(Y2)+","+" "+String.valueOf(X2)+" "+String.valueOf(Y1)+","+" "+String.valueOf(X1)+" "+String.valueOf(Y1)+"))";
		Polygon polygon = (Polygon) reader.read(rangePol);
		/*分别得出四个角点在level层级上的geohash编码，将它们放入集合geoStrings中*/
		Geohash geohash=new Geohash();
		String leftDown=geohash.encodeMaxlevel(Y1, X1, level);
		String leftUp=geohash.encodeMaxlevel(Y2, X1,level);
		String rightUp=geohash.encodeMaxlevel(Y2, X2, level);
		String rightDown=geohash.encodeMaxlevel(Y1, X2, level);
		TreeSet<String> tr = new TreeSet<String>();
		tr.add(leftDown);
		tr.add(leftUp);
		tr.add(rightUp);
		tr.add(rightDown);
		String [] geoStrings=new String[tr.size()];
		for(int i=0;i<geoStrings.length;i++){
			geoStrings[i]=tr.pollFirst();
		}
		/*遍历geoStrings集合，依次从level层级上开始划分，得到一个近似于查询范围的geohash集合TreeSet.rangearrayList
		 * 修改后的查询处理方法与修改前的查询方法结构一致，只是从level层级上划分geohash的方法有所不同。
		 * 将在Treeset中说明
		 * */
		for(int i=0;i<geoStrings.length;i++){
			if(TreeTest.Choose(polygon, geoStrings[i])){
				divRange(geoStrings[i],polygon,level,level1);
			}			
		}
		return TreeTest.rangearrayList;		
	}
	private void divRange(String string,Polygon polygon,int level,int level1) throws ParseException {
		TreeNode root=new TreeNode();
		root=TreeTest.createTree(root,string,level1);
		TreeTest test=new TreeTest();
		test.geohashSearchFunc1(polygon,root,level,level1);
	}
	/*修改后的范围处理方法*/
	private ArrayList<String> pointRanges(double X1,double Y1,double X2,double Y2) throws ParseException{
		double lonlength;
		double latlength;
		double l,l1;
		double y,x;
		int level,level1;
		if(X1<X2){
			lonlength=X2-X1;
		}
		else {
			lonlength=X2-X1+360;
		}
		latlength=Y2-Y1;
		if(lonlength>=latlength){
			l=(2*Math.floor(Logarithm.log(360/lonlength, 2))-1);		
			y=180/(Math.pow(2, (l+1)/2));			
			if(latlength<=y){
				level=(int) (l+1);
			}
			else {
				level=(int) l;
			}
			l1=2*Math.floor(Logarithm.log(180/latlength, 2));
			x=360/(Math.pow(2, (l1+2)/2));
			if(lonlength<=x){
				level1=(int) (l1+1);
			}
			else{
				level1=(int) l1;
			}
		}
		else{
			l=2*Math.floor(Logarithm.log(180/latlength, 2));
			x=360/(Math.pow(2, (l+2)/2));
			if(lonlength<=x){
				level=(int) (l+1);
			}
			else{
				level=(int) l;
			}
			l1=(2*Math.floor(Logarithm.log(360/lonlength, 2))-1);
			y=180/(Math.pow(2, (l+1)/2));	
			if(latlength<=y){
				level1=(int) (l1+1);
			}
			else {
				level1=(int) l1;
			}
		}
		Geohash geohash=new Geohash();
		String leftDown=geohash.encodeMaxlevel(Y1, X1, level);
		String leftUp=geohash.encodeMaxlevel(Y2, X1,level);
		String rightUp=geohash.encodeMaxlevel(Y2, X2, level);
		String rightDown=geohash.encodeMaxlevel(Y1, X2, level);
		TreeSet<String> tr = new TreeSet<String>();
		tr.add(leftDown);
		tr.add(leftUp);
		tr.add(rightUp);
		tr.add(rightDown);
		String [] geoStrings=new String[tr.size()];
		for(int i=0;i<geoStrings.length;i++){
			geoStrings[i]=tr.pollFirst();
		}
		GeometryFactory geometryFactory=new GeometryFactory();
		WKTReader reader = new WKTReader(geometryFactory);
		String rangePol="POLYGON(("+String.valueOf(X1)+" "+String.valueOf(Y1)+","+" "+String.valueOf(X1)+" "+String.valueOf(Y2)+","+" "+String.valueOf(X2)+" "+String.valueOf(Y2)+","+" "+String.valueOf(X2)+" "+String.valueOf(Y1)+","+" "+String.valueOf(X1)+" "+String.valueOf(Y1)+"))";
		Polygon polygon = (Polygon) reader.read(rangePol);
		for(int i=0;i<geoStrings.length;i++){
			if(TreeTest.Choose(polygon, geoStrings[i])){
				TreeNode root=new TreeNode();
				root=TreeTest.createTree(root,geoStrings[i],level1);
				TreeTest test=new TreeTest();
				test.pointRangeFunc1(polygon,root,level,level,level1);
			}			
		}
		return TreeTest.pointrangearrayList;
	}
	/*基于点的范围查询*/
	public ArrayList<String> pointRangeQuery(double X1,double Y1,double X2,double Y2) throws Exception{
		Geohash geohash=new Geohash();
		ArrayList<String> rangeArray=new ArrayList<String>();
		ArrayList<String> arrayList=new ArrayList<String>();
//		rangeArray=new PointRangeQuery().searchGeohash(X1, Y1, X2, Y2);
		rangeArray=new PointRangeQuery().pointRanges(X1, Y1, X2, Y2);
		for(int i=0;i<rangeArray.size();i++){
			String geohashString=rangeArray.get(i);
			ArrayList<String> result=new ArrayList<String>();
			/*result集合为最终以HBase32编码集合近似查询范围的几何*/
			result=geohash.resultArray(geohashString);
			HBaseSQLDriverTest test=new HBaseSQLDriverTest();
			for(int j=0;j<result.size();j++){
				String like=result.get(j);
				ArrayList<String> resultarray=new ArrayList<String>();
				/*resultarray为最终Like前缀匹配且二次过滤后的点集*/
				resultarray=test.query("select rowkey from suijidian where rowkey LIKE '"+like+"%'"+" and X between "+String.valueOf(X1)+" and "+String.valueOf(X2)+" and Y between "+String.valueOf(Y1)+" and "+String.valueOf(Y2));
			    arrayList.addAll(resultarray);
			}
		}
		return arrayList;
	}
	public static void main(String args[]) throws Exception{
		long startTime = System.currentTimeMillis();//获取当前时间
		PointRangeQuery rangeQuery=new PointRangeQuery();	
		ArrayList<String> result=new ArrayList<String>();	
		for(int i=0;i<100;i++){
			double X=FictitiousPolgon.getRandomNum(-180, 175);
			double Y=FictitiousPolgon.getRandomNum(-90, 85);
			double zengliang1=FictitiousPolgon.getRandomNum(1,5);
			double zengliang2=FictitiousPolgon.getRandomNum(1,5);
			result=rangeQuery.pointRangeQuery(X,Y,X+zengliang1,Y+zengliang2);
//			TreeTest.rangearrayList.clear();
			TreeTest.pointrangearrayList.clear();
		}
		long endTime = System.currentTimeMillis();
		System.out.println("程序运行时间："+(endTime-startTime)/100+"ms");	
	}

}
